package com.ccsu.mymarket.service.Impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ccsu.mymarket.controller.utils.DataUtils;
import com.ccsu.mymarket.dao.OrderInfoDao;
import com.ccsu.mymarket.entity.*;
import com.ccsu.mymarket.entity.message.Meta;
import com.ccsu.mymarket.entity.message.Result;
import com.ccsu.mymarket.exception.MyException;
import com.ccsu.mymarket.service.BookService;
import com.ccsu.mymarket.service.OrderService;
import com.ccsu.mymarket.service.ShoppingCartService;
import com.ccsu.mymarket.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

@Service
public class OrderServiceImpl extends ServiceImpl<OrderInfoDao, OrderInfo> implements OrderService {

    private final OrderInfoDao orderInfoDao;
    private final UserService userService;
    private final BookService bookService;
    private final ShoppingCartService cartService;

    public OrderServiceImpl(@Autowired OrderInfoDao orderInfoDao, @Autowired UserService userService, @Autowired BookService bookService, @Autowired ShoppingCartService cartService) {
        this.orderInfoDao = orderInfoDao;
        this.userService = userService;
        this.bookService = bookService;
        this.cartService = cartService;
    }

    @Override
    public List<OrderInfo> getOrderList() {
        return null;
    }


    /**
     * 购物车批量下单，开启了事务
     * 通过图书id + 用户id 获得相关的 购物车对象 列表 -> 对各条记录分别建立订单对象，生成下单时间
     * 对各图书，遍历查询其库存是否充足，不足则返回错误提示
     * 通过购物车信息建立订单，生成时间，计算各订单总价
     * 将各订单总价相加，计算批量下单的总价格，查找用户余额是否充足
     * 余额充足时，扣钱，订单状态设为 1-已支付，生成支付时间，插入数据库
     * 删除购物车中相应记录
     *
     * @param bookIds 商品id列表
     * @param userId  用户id
     * @return 下单是否成功
     */
    @Override
    @Transactional
    public boolean batchAddOrder(List<Integer> bookIds, Integer userId) throws MyException {

        List<ShoppingCart> cartList = cartService.list(new LambdaQueryWrapper<ShoppingCart>()
                .eq(ShoppingCart::getAccId, userId).in(ShoppingCart::getBookId, bookIds));
        List<OrderInfo> orderInfoList=buildOrdersByBookId(cartList,userId);
//        检查库存
        for (OrderInfo orderInfo : orderInfoList) {
            if (checkBookStock(orderInfo.getBookId(),orderInfo.getNum())<0)
                throw new MyException("id为"+orderInfo.getBookId()+"的商品库存不足!");
        }
//        检查用户余额
        Double orderPriceSum= 0.00;
        for (OrderInfo orderInfo : orderInfoList) {
            orderPriceSum += orderInfo.getSum();
        }
        if (checkUserPurse(userId,orderPriceSum)<0)
            throw new MyException("用户余额不足!");

//        检查完毕，原子性操作，使用事务保证一致成功或失败
        try {
            //        下单
            if (orderInfoDao.batchAddOrder(orderInfoList)<1)
                throw new RuntimeException("添加订单操作影响条数小于1");
        }catch (RuntimeException e){
            log.error(e.getMessage());
            throw new MyException("下单时,添加订单失败!");
        }
        try {
            //        修改商品库存
            if (orderInfoDao.batchUpdateStock(orderInfoList)<1)
                throw new RuntimeException("修改库存操作影响条数小于1");
        }catch (RuntimeException e){
            log.error(e.getMessage());
            throw new MyException("下单时,修改库存失败!");
        }
        try {
            //        修改用户余额
            if (orderInfoDao.batchUpdatePurse(userId,orderPriceSum)<1)
                throw new RuntimeException("修改用户余额操作影响条数小于1");
        }catch (RuntimeException e){
            log.error(e.getMessage());
            throw new MyException("下单时,修改用户余额失败!");
        }
        try {
            //        对购物车,删除相关记录
            List<Integer> cartIds=cartList.stream().map(ShoppingCart::getId).collect(Collectors.toList());
            cartService.removeByIds(cartIds);
        }catch (RuntimeException e){
            log.error(e.getMessage());
            throw new MyException("下单删除购物车记录失败!");
        }
        return true;
    }

//    批量下单的工具方法，用于使用 购物车对象列表 创建订单列表
    private List<OrderInfo> buildOrdersByBookId(List<ShoppingCart> cartList,Integer userId){
        List<OrderInfo> orderList = new ArrayList<>();
        String orderTime = DataUtils.getDateTime(1);
        for (ShoppingCart cart : cartList) {
            OrderInfo order = new OrderInfo();
            order.setOrderTime(orderTime);
            order.setAcc(userId);
            order.setBookId(cart.getBookId());
            order.setAddress(1);
            order.setNote(null);
            order.setPrice(cart.getPrice());
            order.setNum(cart.getNum());
            order.setSum(cart.getNum() * cart.getPrice());
            order.setCoverImg(cart.getCoverImg());
            order.setState(1);

            orderList.add(order);
        }
        return orderList;
    }

    @Override
    public Result updateOrder(OrderInfo order) {
        String newTime = DataUtils.getDateTime(1);

        switch (order.getState()) {
            case 2:
                order.setDeliverTime(newTime);
                break;
            case 3:
                order.setReceiveTime(newTime);
                break;
            case 4: {
                order.setCommentTime(newTime);
                order.setComment(order.getComment());
                break;
            }
        }

        Integer row = orderInfoDao.update(order, new LambdaUpdateWrapper<OrderInfo>()
                .set(OrderInfo::getState, order.getState())
                .set(order.getDeliverTime() != null, OrderInfo::getDeliverTime, newTime)
                .set(order.getReceiveTime() != null, OrderInfo::getReceiveTime, newTime)
                .set(order.getCommentTime() != null, OrderInfo::getCommentTime, newTime)
                .set(order.getComment() != null, OrderInfo::getComment, order.getComment())
                .eq(OrderInfo::getId, order.getId()));
        if (row == 1)
            return new Result(new Meta(200, "操作成功！"), null);
        return new Result(new Meta(500, "操作失败！"), null);
    }

    @Override
    public List<Map> getComments(Integer id) {
        List<OrderInfo> commentList = orderInfoDao.selectList(new LambdaQueryWrapper<OrderInfo>()
                .eq(OrderInfo::getBookId, id)
                .select(OrderInfo::getComment, OrderInfo::getCommentTime));
        List<Map> commentDataList=new ArrayList<>();
        for (OrderInfo orderInfo : commentList) {
            Map comment=new HashMap();
            comment.put("comment",orderInfo.getComment());
            comment.put("commentTime",orderInfo.getCommentTime());
            commentDataList.add(comment);
        }
        return commentDataList;
    }

    @Override
    public List<OrderInfo> getOrderByUserId(Integer id) {
        Integer roleId = userService.getOne(new LambdaQueryWrapper<User>()
                .eq(User::getId, id).select(User::getRole)).getRole();
        switch (roleId) {
//            买家
            case 1:
                return orderInfoDao.getOrderForBuyer(id);
//             商家，卖家
            case 2:
//                商家id->店铺id->商品id->订单
                List<Integer> bookIds = userService.getShopBookIds(id);
                return orderInfoDao.getOrderForSeller(bookIds);
        }
        return null;
    }

    @Override
    public Double checkUserPurse(Integer id, Double sum) {
        Double purse = userService.getOne(new LambdaQueryWrapper<User>()
                .eq(User::getId, id).select(User::getPurse)).getPurse();
        return purse - sum;
    }

    @Override
    public Integer checkBookStock(Integer id, Integer num) {
        Integer stock = bookService.getOne(new LambdaQueryWrapper<Book>()
                .eq(Book::getId, id).select(Book::getStock)).getStock();
        return stock - num;
    }


}
